package com.zhichat.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhichat.dao.ChatSessionDao;
import com.zhichat.dao.ChatUserSessionDao;
import com.zhichat.dao.ContactInfoDao;
import com.zhichat.dao.UserInfoDao;
import com.zhichat.document.ChatMsgDoc;
import com.zhichat.entity.*;
import com.zhichat.infrastructure.Enums.*;
import com.zhichat.infrastructure.config.OSSConfig;
import com.zhichat.infrastructure.config.ZhiChatGlobalUtil;
import com.zhichat.infrastructure.constants.Constants;
import com.zhichat.infrastructure.exception.http.CommonException;
import com.zhichat.infrastructure.redis.Keys;
import com.zhichat.infrastructure.redis.RedisRepository;
import com.zhichat.infrastructure.redis.rediskey.Key;
import com.zhichat.infrastructure.redis.rediskey.ZhiChat;
import com.zhichat.infrastructure.util.OSSClient;
import com.zhichat.infrastructure.util.ThreadLocalCache;
import com.zhichat.infrastructure.util.Utils;
import com.zhichat.service.AdminUserService;
import com.zhichat.service.SysConfigService;
import com.zhichat.service.UserInfoService;
import com.zhichat.web.api.PageUtils;
import com.zhichat.web.dto.*;
import com.zhichat.web.dto.dao.AdminUserListQuery;
import com.zhichat.web.socket.ChannelContextCommon;
import com.zhichat.web.socket.GlobalMsgHandle;
import com.zhichat.web.vo.AdminUserInfoVO;
import com.zhichat.web.vo.LoginVO;
import com.zhichat.web.vo.UserInfoVO;
import com.zhichat.web.vo.ws.MsgVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService {

    private final RedisRepository redisRepository;
    private final AdminUserService adminUserService;
    private final ContactInfoDao contactInfoDao;
    private final OSSConfig ossConfig;
    private final SysConfigService sysConfigService;
    private final ChatSessionDao chatSessionDao;
    private final ChatUserSessionDao chatUserSessionDao;
    private final MongoTemplate mongoTemplate;
    private final ZhiChatGlobalUtil zhiChatGlobalUtil;
    private final GlobalMsgHandle globalMsgHandle;
    private final ChannelContextCommon channelContextCommon;

    //region test1
    private void checkCodeKey(String checkCodeUniqueId, String code) {
        Key key = new ZhiChat(Keys.CHECK_CODE);
        String checkCode = redisRepository.get(key, checkCodeUniqueId);
        if (Objects.isNull(checkCode)) {
            throw new CommonException("验证码已过期");
        } else {
            // 验证失败，删除redis验证码信息
            if (!checkCode.equalsIgnoreCase(code)) {
                redisRepository.del(key, checkCodeUniqueId);
                throw new CommonException("验证码验证失败");
            }
        }
        // 校验成功，删除redis验证信息
        redisRepository.del(key, checkCodeUniqueId);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public boolean register(RegisterDTO dto) {
        // 验证码验证
        checkCodeKey(dto.getCheckCodeUniqueId(), dto.getCode());
        // 账号（手机号）注册验证
        LambdaQueryWrapper<UserInfoEntity> query = Wrappers.lambdaQuery(UserInfoEntity.class);
        query.select(UserInfoEntity::getStatus)
                .eq(UserInfoEntity::getPhone, dto.getPhone());
        UserInfoEntity userInfoEntity = baseMapper.selectOne(query);
        if (Objects.nonNull(userInfoEntity)) {
            if (UserStatusEnum.DISABLED.getCode().equals(userInfoEntity.getStatus())) {
                throw new CommonException("手机号已被注册");
            } else {
                throw new CommonException("手机号已被封禁");
            }
        }
        // 保存注册用户信息 - >  mysql
        Long userId = Utils.snowflakeId();
        LocalDateTime nowData = LocalDateTime.now();
        String userId2 = Utils.getUserId(DateUtil.format(nowData, DatePattern.PURE_DATE_PATTERN));
        userInfoEntity = new UserInfoEntity()
                .setId(userId)
                .setUserId(userId2)
                .setNickname(dto.getNickname())
                .setPhone(dto.getPhone())
                .setPassword(SecureUtil.md5(dto.getPassword()))
                .setLastOffTime(LocalDateTimeUtil.toEpochMilli(nowData))
                .setCreateTime(nowData);
        if (baseMapper.insert(userInfoEntity) != 1) {
            throw new CommonException("注册失败");
        }
        // 添加机器人好友
        SysConfigEntity sysConfigInfo = sysConfigService.getSysConfigInfo();
        Long robotId = sysConfigInfo.getRobotId();
        String robotWelcomeMsg = sysConfigInfo.getRobotWelcome();
        String robotNickName = sysConfigInfo.getRobotNickname();
        ContactInfoEntity contactInfo = new ContactInfoEntity();
        contactInfo.setUserId(userId)
                .setContactId(robotId)
                .setContactType(ContactTypeEnum.USER.getCode())
                .setLastUpdateTime(LocalDateTimeUtil.toEpochMilli(nowData))
                .setStatus(ContactStatusEnum.FRIEND.getCode());
        if (1 != contactInfoDao.insert(contactInfo)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 添加与机器人的 会话信息
        String sessionId = Utils.lsMd5(userId, robotId);
        ChatSessionEntity chatSessionEntity = new ChatSessionEntity();
        chatSessionEntity.setId(sessionId)
                .setLastMsg(robotWelcomeMsg)
                .setLastReceiveTime(LocalDateTimeUtil.toEpochMilli(nowData));
        if (1 != chatSessionDao.insert(chatSessionEntity)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 用户会话信息
        ChatUserSessionEntity chatUserSessionEntity = new ChatUserSessionEntity();
        chatUserSessionEntity.setUserId(userId)
                .setReceiverId(robotId)
                .setSessionId(sessionId)
                .setReceiverNickname(robotNickName);
        if (1 != chatUserSessionDao.insert(chatUserSessionEntity)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 添加聊天信息 -> mongodb
        try {
            ChatMsgDoc chatMsgDoc = new ChatMsgDoc();
            chatMsgDoc.setId(Utils.uniqueId())
                    .setSenderId(robotId)
                    .setSenderNickname(robotNickName)
                    .setSendTime(LocalDateTimeUtil.toEpochMilli(nowData))
                    .setReceiverId(userId)
                    .setReceiverType(ContactTypeEnum.USER.getCode())
                    .setSessionId(sessionId)
                    .setMsg(robotWelcomeMsg)
                    .setMsgType(MsgTypeEnum.CHAT.getCode())
                    .setStatus(ChatMsgStatusEnum.SUCCESS.getCode());
            mongoTemplate.insert(chatMsgDoc);
        } catch (Exception e) {
            throw CommonException.MONGO_MODIFY_COMMON_EXCEPTION;
        }
        return true;
    }

    @Override
    public LoginVO login(LoginDTO dto) {
        // 验证码验证
        checkCodeKey(dto.getCheckCodeUniqueId(), dto.getCode());
        // 账号（手机号）登录验证
        LambdaQueryWrapper<UserInfoEntity> query = Wrappers.lambdaQuery(UserInfoEntity.class);
        query.select(UserInfoEntity::getId, UserInfoEntity::getUserId, UserInfoEntity::getPhone, UserInfoEntity::getGender
                        , UserInfoEntity::getPassword, UserInfoEntity::getStatus, UserInfoEntity::getNickname, UserInfoEntity::getAreaCode
                        , UserInfoEntity::getAreaName, UserInfoEntity::getPersonalSignature)
                .eq(UserInfoEntity::getPhone, dto.getPhone());
        UserInfoEntity userInfoEntity = baseMapper.selectOne(query);
        if (Objects.isNull(userInfoEntity)) {
            throw new CommonException("账号不存在");
        }
        if (!userInfoEntity.getPassword().equals(SecureUtil.md5(dto.getPassword()))) {
            throw new CommonException("密码错误");
        }
        if (Objects.equals(UserStatusEnum.NORMAL.getCode(), userInfoEntity.getStatus())) {
            throw new CommonException("账号已被封禁");
        }
        Long userId = userInfoEntity.getId();
        // 判断 是否已在线
        Key heartbeatKey = new ZhiChat(Keys.USER_HEARTBEAT);
        String lastHeartbeatTimeStr = redisRepository.get(heartbeatKey, userId);
        if (StringUtils.hasText(lastHeartbeatTimeStr)) {
            throw new CommonException("账号已在其他地方登录"); // TODO 是否需要做 踢出其他地方登录的账号（需要做一些校验，避免黑客盗号等行为）
        }
        log.info("用户：{} 登录成功，phone：{}，userId：{}", userInfoEntity.getNickname(), userInfoEntity.getPhone(), userId);
        // 跟新用户登录时间
        LambdaUpdateWrapper<UserInfoEntity> updateWrapper = Wrappers.lambdaUpdate(UserInfoEntity.class);
        updateWrapper.set(UserInfoEntity::getLastLoginTime, LocalDateTime.now())
                .eq(UserInfoEntity::getId, userId);
        if (baseMapper.update(null, updateWrapper) != 1) {
            throw new CommonException("登录失败");
        }
        // 验证账号 是否是 管理员账号
        LambdaQueryWrapper<AdminUserEntity> adminUserEntityLambdaQueryWrapper = Wrappers.lambdaQuery(AdminUserEntity.class);
        adminUserEntityLambdaQueryWrapper.select(AdminUserEntity::getUserId)
                .eq(AdminUserEntity::getUserId, userId);
        AdminUserEntity adminUserEntity = adminUserService.getOne(adminUserEntityLambdaQueryWrapper);
        // 生成 token
        String token = zhiChatGlobalUtil.token(userId);
        // 保存登录用户信息 -> redis
        UserToken userToken = new UserToken(
                userId,
                userInfoEntity.getUserId(),
                userInfoEntity.getPhone(),
                userInfoEntity.getNickname(),
                Objects.isNull(adminUserEntity) ? Boolean.FALSE : Boolean.TRUE,
                token
        );
        Key tokenKey = new ZhiChat(Keys.TOKEN, Duration.ofSeconds(Constants.TOKEN_EXPIRE_TIME));
        redisRepository.set(tokenKey, JSON.toJSONString(userToken), userId);
        // 保存登录用户 所有联系人（群组、用户） -> redis
        setContactInfo2Redis(userId);
        // 封装返回给前端
        LoginVO resVo = new LoginVO();
        BeanUtils.copyProperties(userToken, resVo);
        resVo.setUserId(userToken.getUserId());
        BeanUtils.copyProperties(userInfoEntity, resVo, "userId", "userId2", "phone", "nickname", "token", "isAdmin");
        return resVo;
    }
    //endregion

    //region test2
    /**
     * set 用户联系人信息  - >  redis
     */
    private void setContactInfo2Redis(Long userId) {
        // 清空 redis 当前可能存在的 contact 数据
        Key userContactTmpKey = new ZhiChat(Keys.CONTACT_USER);
        redisRepository.del(userContactTmpKey, userId);
        Key groupContactTmpKey = new ZhiChat(Keys.CONTACT_GROUP);
        redisRepository.del(groupContactTmpKey, userId);
        // 获取我的所有 好友 状态的联系人(用户和群组)
        LambdaQueryWrapper<ContactInfoEntity> contactQuery = Wrappers.lambdaQuery(ContactInfoEntity.class);
        contactQuery.select(ContactInfoEntity::getContactId, ContactInfoEntity::getContactType)
                .eq(ContactInfoEntity::getUserId, userId)
                .in(ContactInfoEntity::getStatus, ContactStatusEnum.FRIEND.getCode(), ContactStatusEnum.BLACKLISTED_BY_FRIEND.getCode(), ContactStatusEnum.DELETED_BY_FRIEND.getCode());
        List<ContactInfoEntity> contactInfoEntities = contactInfoDao.selectList(contactQuery);
        if (!CollectionUtils.isEmpty(contactInfoEntities)) {
            Map<Integer, List<ContactInfoEntity>> listMap = contactInfoEntities.stream().collect(Collectors.groupingBy(ContactInfoEntity::getContactType));
            // 将 所有 contact Id 放入redis，设置 1天过期时间（和登录token过期时间相同）
            List<ContactInfoEntity> userContactList = listMap.get(ContactTypeEnum.USER.getCode());
            if (!CollectionUtils.isEmpty(userContactList)) {
                Key userContactKey = new ZhiChat(Keys.CONTACT_USER, Duration.ofSeconds(Constants.TOKEN_EXPIRE_TIME));
                redisRepository.addAll(userContactKey, userContactList.stream().map(ContactInfoEntity::getContactId).collect(Collectors.toSet()), userId);
            }
            // 将 所有 group Id 放入redis，设置 1天过期时间（和登录token过期时间相同）
            List<ContactInfoEntity> groupContactList = listMap.get(ContactTypeEnum.GROUP.getCode());
            if (!CollectionUtils.isEmpty(groupContactList)) {
                Key groupContactKey = new ZhiChat(Keys.CONTACT_GROUP, Duration.ofSeconds(Constants.TOKEN_EXPIRE_TIME));
                redisRepository.addAll(groupContactKey, groupContactList.stream().map(ContactInfoEntity::getContactId).collect(Collectors.toSet()), userId);
            }
        }
    }

    @Override
    public UserInfoVO detail(Long userId) {
        LambdaQueryWrapper<UserInfoEntity> wrapper = Wrappers.lambdaQuery(UserInfoEntity.class);
        wrapper.eq(UserInfoEntity::getId, userId);
        UserInfoEntity userInfo = baseMapper.selectOne(wrapper);
        if (Objects.isNull(userInfo)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 区分 好友 和 非好友 查询时，能获取的信息
        UserInfoVO vo = new UserInfoVO();
        vo.setUserId(userId);
        BeanUtils.copyProperties(userInfo, vo, "userId");
        vo.setUserId2(userInfo.getUserId());
        // 查询自己的信息
        if (Objects.equals(userId, ThreadLocalCache.getUserId())) {
            vo.setAdmin(ThreadLocalCache.getUserToken().getIsAdmin());
            return vo;
        }
        // 查询联系人的信息
        vo.setContactStatus(ContactStatusEnum.NON_FRIEND.getCode());
        LambdaQueryWrapper<ContactInfoEntity> contactWrapper = Wrappers.lambdaQuery(ContactInfoEntity.class);
        contactWrapper.eq(ContactInfoEntity::getUserId, userId)
                .eq(ContactInfoEntity::getContactId, ThreadLocalCache.getUserId());
        ContactInfoEntity contactInfoEntity = contactInfoDao.selectOne(contactWrapper);
        if (Objects.nonNull(contactInfoEntity) && Objects.equals(contactInfoEntity.getStatus(), ContactStatusEnum.FRIEND.getCode())) {
            vo.setContactStatus(ContactStatusEnum.FRIEND.getCode());
        }
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserInfoVO updateUserInfo(UserInfoUpdateDTO dto) throws IOException {
        MultipartFile userAvatarFile = dto.getUserAvatarFile();
        MultipartFile userAvatarCoverFile = dto.getUserAvatarCoverFile();
        if (userAvatarFile.isEmpty() || userAvatarCoverFile.isEmpty()) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        String nickname = dto.getNickname();
        long curTime = System.currentTimeMillis();
        // 上传头像
        InputStream userAvatarFileIn = userAvatarFile.getInputStream();
        InputStream userAvatarCoverFileIn = userAvatarCoverFile.getInputStream();
        if (!OSSClient.uploadFile(userAvatarFileIn, Constants.USER_AVATAR_OSS_FOLDER, Objects.requireNonNull(ThreadLocalCache.getUserId()).toString().concat(Constants.IMG_SUF_PNG), ossConfig, null)
                || !OSSClient.uploadFile(userAvatarCoverFileIn, Constants.USER_AVATAR_OSS_FOLDER, Objects.requireNonNull(ThreadLocalCache.getUserId()).toString().concat(Constants.IMG_SUF_PNG.concat(Constants.COVER_SUF_JPG)), ossConfig, null)) {
            throw CommonException.FILE_OPERATE_COMMON_EXCEPTION;
        }
        // 修改前 查询数据（为后面修改 会话昵称做准备）
        LambdaQueryWrapper<UserInfoEntity> queryWrapper = Wrappers.lambdaQuery(UserInfoEntity.class);
        queryWrapper.select(UserInfoEntity::getNickname)
                .eq(UserInfoEntity::getId, ThreadLocalCache.getUserId());
        UserInfoEntity userInfoEntity = baseMapper.selectOne(queryWrapper);
        // 修改数据
        UserInfoEntity updateEntity = new UserInfoEntity();
        BeanUtils.copyProperties(dto, updateEntity);
        LambdaUpdateWrapper<UserInfoEntity> updateWrapper = Wrappers.lambdaUpdate(UserInfoEntity.class);
        updateWrapper.eq(UserInfoEntity::getId, ThreadLocalCache.getUserId());
        if (0 == baseMapper.update(updateEntity, updateWrapper)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 是否需要 修改 会话中的昵称？
        boolean updateNickNameFlag = !Objects.equals(userInfoEntity.getNickname(), nickname);
        if (updateNickNameFlag) {
            // 修改 redis 的登录信息
            UserToken userToken = ThreadLocalCache.getUserToken();
            userToken.setNickname(nickname);
            ThreadLocalCache.putUserToken(userToken);
            Key key = new ZhiChat(Keys.TOKEN, Duration.ofSeconds(Constants.TOKEN_EXPIRE_TIME));
            redisRepository.set(key, JSON.toJSONString(userToken), userToken.getUserId());
            // 【跟新 用户昵称 冗余在其他表的信息】 和 【发送ws消息】
            LambdaUpdateWrapper<ChatUserSessionEntity> chatUserSessionUpdate = Wrappers.lambdaUpdate(ChatUserSessionEntity.class);
            chatUserSessionUpdate.eq(ChatUserSessionEntity::getReceiverId, ThreadLocalCache.getUserId())
                    .set(ChatUserSessionEntity::getReceiverNickname, nickname);
            if (chatUserSessionDao.selectCount(Wrappers.lambdaQuery(ChatUserSessionEntity.class).eq(ChatUserSessionEntity::getReceiverId, ThreadLocalCache.getUserId()))
                    != chatUserSessionDao.update(null, chatUserSessionUpdate)) {
                throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
            }
            // 发送ws消息
            Key key1 = new ZhiChat(Keys.CONTACT_USER);
            List<Long> members = redisRepository.members(key1, Long.class, ThreadLocalCache.getUserId());
            if (!CollectionUtils.isEmpty(members)) {
                members.forEach(member -> {
                    MsgVO<String> msgVO = new MsgVO<>();
                    msgVO.setMsgType(MsgTypeEnum.UPDATE_GROUP_NICKNAME.getCode())
                            .setSendTime(curTime)
                            .setReceiverId(member)
                            .setReceiverType(ContactTypeEnum.USER.getCode())
                            .setData(nickname);
                    globalMsgHandle.sendHandler(msgVO);
                });
            }
        }
        // 返回数据（页面展示）
        UserInfoVO resVo = new UserInfoVO();
        BeanUtils.copyProperties(ThreadLocalCache.getUserToken(), resVo);
        BeanUtils.copyProperties(userInfoEntity, resVo);
        BeanUtils.copyProperties(dto, resVo);
        return resVo;
    }

    @Override
    public boolean updatePassword(String oldPassword, String newPassword) {
        if (!StringUtils.hasText(oldPassword) || !StringUtils.hasText(newPassword)) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        if (Objects.equals(oldPassword, newPassword)) {
            throw new CommonException("新旧密码不能相同");
        }
        Long userId = ThreadLocalCache.getUserId();
        // 校验 原密码是否正确
        LambdaQueryWrapper<UserInfoEntity> queryWrapper = Wrappers.lambdaQuery(UserInfoEntity.class);
        queryWrapper.select(UserInfoEntity::getPassword)
                .eq(UserInfoEntity::getId, userId);
        UserInfoEntity userInfoEntity = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(userInfoEntity) || !Objects.equals(SecureUtil.md5(oldPassword), userInfoEntity.getPassword())) {
            throw new CommonException("密码验证失败");
        }
        // 修改密码
        LambdaUpdateWrapper<UserInfoEntity> updateWrapper = Wrappers.lambdaUpdate(UserInfoEntity.class);
        updateWrapper.eq(UserInfoEntity::getId, userId)
                .eq(UserInfoEntity::getPassword, SecureUtil.md5(oldPassword))
                .set(UserInfoEntity::getPassword, SecureUtil.md5(newPassword));
        if (0 == baseMapper.update(null, updateWrapper)) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        // 强制退出
        logout(userId);
        return true;
    }

    @Override
    public boolean logout() {
        Long userId = ThreadLocalCache.getUserId();
        // 退出登录
        logout(userId);
        return true;
    }

    private void logout(Long userId) {
        // 退出ws（用户channel关闭，群channel内的这个用户channel会自动关闭）
        channelContextCommon.removeUserChannel(userId);
        // 清空缓存
        Key userContactTmpKey = new ZhiChat(Keys.CONTACT_USER);
        redisRepository.del(userContactTmpKey, userId);
        Key groupContactTmpKey = new ZhiChat(Keys.CONTACT_GROUP);
        redisRepository.del(groupContactTmpKey, userId);
        Key tokenKey = new ZhiChat(Keys.TOKEN);
        redisRepository.del(tokenKey, ThreadLocalCache.getUserId());
        Key heartbeatKey = new ZhiChat(Keys.USER_HEARTBEAT);
        redisRepository.del(heartbeatKey, userId);
    }

    @Override
    public PageUtils<AdminUserInfoVO> userListOfAdmin(AdminUserQueryDTO dto) {
        AdminUserListQuery adminConditionQuery = new AdminUserListQuery();
        BeanUtils.copyProperties(dto, adminConditionQuery);
        adminConditionQuery.setStart((dto.getPageNum() - 1) * dto.getPageSize());
        adminConditionQuery.setSize(dto.getPageSize());
        // TODO 处理 online 条件 及 返回数据
        List<AdminUserInfoVO> dataList = baseMapper.getUserInfoListOfAdmin(adminConditionQuery);
        return new PageUtils<>(dataList, Math.toIntExact(baseMapper.selectCount(null))
                , dto.getPageSize(), dto.getPageNum());
    }

    @Override
    public boolean isEnable(Long userId, Integer status) {
        if (Objects.isNull(UserStatusEnum.getEnumByCode(status))) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        // 查询用户状态
        LambdaQueryWrapper<UserInfoEntity> queryWrapper = Wrappers.lambdaQuery(UserInfoEntity.class);
        queryWrapper.select(UserInfoEntity::getStatus)
                .eq(UserInfoEntity::getUserId, userId);
        UserInfoEntity userInfoEntity = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(userInfoEntity)) {
            throw CommonException.PARAMETER_COMMON_EXCEPTION;
        }
        // 修改用户状态
        LambdaUpdateWrapper<UserInfoEntity> updateWrapper = Wrappers.lambdaUpdate(UserInfoEntity.class);
        updateWrapper.eq(UserInfoEntity::getUserId, userId)
                .eq(UserInfoEntity::getStatus, userInfoEntity.getStatus())
                .set(UserInfoEntity::getStatus, status);
        int update = baseMapper.update(null, updateWrapper);
        if (0 == update) {
            throw CommonException.DB_MODIFY_COMMON_EXCEPTION;
        }
        return true;
    }

    @Override
    public boolean forcedOffline(Long userId) {
//        logout(userId);
        MsgVO<String> msgVO = new MsgVO<String>()
                .setMsgType(MsgTypeEnum.FORCE_OFFLINE.getCode())
                .setReceiverId(userId)
                .setReceiverType(ContactTypeEnum.USER.getCode());
        globalMsgHandle.sendHandler(msgVO);
        return true;
    }
    //endregion

    @Override
    public LoginVO getCurUserInfo() {
        Long userId = ThreadLocalCache.getUserId();
        UserInfoEntity userInfoEntity = baseMapper.selectById(userId);
        if (Objects.isNull(userInfoEntity)) {
            throw CommonException.SYS_COMMON_EXCEPTION;
        }
        Key key = new ZhiChat(Keys.TOKEN);
        UserToken userToken = redisRepository.get(key, UserToken.class, userId);
        if (Objects.isNull(userToken)) {
            throw CommonException.SYS_COMMON_EXCEPTION;
        }
        LoginVO resVo = new LoginVO();
        BeanUtils.copyProperties(userInfoEntity, resVo, "userId");
        resVo.setUserId2(userInfoEntity.getUserId());
        resVo.setUserId(userInfoEntity.getId());
        resVo.setIsAdmin(userToken.getIsAdmin());
        resVo.setToken(userToken.getToken());
        return resVo;
    }

    @Override
    @Transactional
    public String test() {
        UserInfoEntity userInfo = new UserInfoEntity()
                .setId(Utils.snowflakeId())
                .setUserId(Utils.uniqueId())
                .setPhone("15956926269")
                .setNickname("15956")
                .setPassword("6666")
                .setLastOffTime(System.currentTimeMillis());


        return "";
    }
}